/**
 * @class   wosh::DeviceManager
 * @brief   Core module managing devices (wosh::Device) of local host.
 *
 * \image html diagrams/DeviceManager.png "wosh::DeviceManager UML diagram"
 *
 *
 * @ingroup CoreModules
 ****************************************************************************
 * @version 0.8.499 $Id: DeviceManager.h 2827 2010-08-02 11:01:48Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_core
 * \htmlonly <hr/> \endhtmlonly
 * \section page_core_devices Devices
 *
 * wosh::DeviceManager is a distributed component hosting information about
 * devices available to the WOSH system. Information are hold by wosh::Device
 * object.
 *
 * [..]
 *
 * \see wosh::DeviceManager
 * \see wosh::Device
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_DeviceManager_H__
 #define __WOSH_Core_DeviceManager_H__

 #include <woshDefs.h>
 #include <core/WoshModule.h>
 #include <core/Containers.h>
 #include <core/SharedMemoryEpidemic.h> //TEMP
 #include <core/Device.h>
 #include <core/Fact.h>


namespace wosh {

 #define _DeviceManager_NAME							"DeviceManager"
 #define _DeviceManager_URI								":Devices"

 #define _DeviceManager_DSM_NAME						"Core_Devices"

 #define _DeviceManager_KEY_Devices						"Devices"
 #define _DeviceManager_KEY_EventLogMaxSize				"EventLogMaxSize"
 #define _DeviceManager_KEY_EventLogLocallyOnly			"EventLogLocallyOnly"

 #define _DeviceManager_DEFAULT_EventLogMaxSize			400


 #define _DeviceManager_METHOD_ListDevices				"list"
 #define _DeviceManager_METHOD_LoadDevice				"load"
 #define _DeviceManager_METHOD_ListSupportedDevices		"list_supported"

 #define _DeviceManager_METHOD_register					"register"
 #define _DeviceManager_METHOD_unregister				"unregister"

 #define _DeviceManager_METHOD_fake_event				"fake_event"
 #define _DeviceManager_METHOD_getdevice				"getdevice"
 #define _DeviceManager_METHOD_GetListByType			"list_by_type"

 #define _DeviceManager_METHOD_eventslog				"eventslog"
 #define _DeviceManager_METHOD_clear_log				"clear_log"

 #define _DeviceManager_EVENT_DeviceUpdated				"device_updated"


class Bundle;
class WoshKernel;

class DeviceManager : public WoshModule
 {
	WOSH_MODULE(wosh::DeviceManager)

	typedef MapT<std::string, Device*> tStrDeviceMap;
	typedef ListT<Message*> tMessageList;


	protected:
		/**
		 * @brief  Default constructor. Call base constructor and initialize some properties and hosted methods.
		 * @param parent [in] WoshKernel singleton, passed to WoshModule constructor
		 * @note   Called by WoshKernel only. Static getter (gamma singleton) will return NULL until kernel is created.
		 */
		DeviceManager( const WoshKernel* parent = NULL );

		/**
		 * @brief  Call base class implementation and create the Device Bus (wosh.Bus.Devices).
		 *         DSM is initialized.
		 * @return result of WoshModule::onKernelInitializing() + bus-creation result
		 */
		WRESULT onKernelInitializing();

		WRESULT onKernelStopping();

		friend class wosh::WoshKernel;

	public:
		/**
		 * @brief  Destructor. Devices and Events dataset are destroyed.
		 */
		virtual ~DeviceManager();


/** @name Public methods (bundles)
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Register a Device. If a Device with same name exists, it is updated. Reentrant.
		 * @param device [in] the device object to be registered, ownership is acquired
		 * @return WRET_ERR_PARAM if argument is NULL or its name is empty; WRET_OK else
		 * @see    registerDevice_()
		 */
		WRESULT registerDevice( Device* device );
		/**
		 * @brief  Register a set of Devices. Reentrant.
		 * @param devices [in] the device objects to be registered, ownership is acquired
		 * @return WRET_ERR_PARAM if no devices were registered; WRET_OK else
		 * @see    registerDevice()
		 */
		WRESULT registerDevices( std::vector<Device*>& devices );
		/**
		 * @brief  UnRegister a Device. Reentrant.
		 * @param devName [in] the name of the device to be removed
		 * @return WRET_ERR_PARAM if device was not found or name is empty; WRET_OK else
		 * @see    registerDevice_()
		 */
		WRESULT unRegisterDevice( const std::string& devName );
		/**
		 * @brief  UnRegister all Device owned by argument. Reentrant.
		 * @param ownerName [in] the name of the devices' owner, all device of this owner will be removed
		 * @return WRET_ERR_PARAM if no devices were found or name is empty; WRET_OK else
		 */
		WRESULT unRegisterDevicesOf( const std::string& ownerName );

		/**
		 * @brief Evaluate if a Device exists. Reentrant.
		 * @param deviceName [in] the name of the device to be checked
		 * @return true if a Device with same name exists; false else
		 */
		bool exists( const std::string& deviceName ) const;
		/**
		 * @brief Get the Interface offered (supported) by a Device. Reentrant.
		 * @param deviceName [in] the name of the device to be evaluated
		 * @param interfaces [out] the interface implemented by the device
		 * @return WRET_ERR_PARAM if device was not found or name is empty; WRET_OK else
		 */
		WRESULT getInterfacesOf( const std::string& deviceName, InterfacesProvider* interfaces );

//@}
/** @name Public methods (loaders)
 * @{
 ******************************************************************************/
	public:
		///@todo TO BE REDESIGNED
		static void busMessageForBundleDevices( const Message& message, const Bus* source, Bundle* bundle, MethodsProvider& Methods, LogContext& Log, BusConnector& BusCore, BusConnector& BusDevices );
//@}
/** @name Message Events (incoming message)
 * @{
 ******************************************************************************/
	public:
		void busMessage( const Message& message, const Bus* source );
//@}
/** @name IPropertiesProviderListener interface
 * @{
 ******************************************************************************/
 	protected:
		bool updatingProperty( bool& do_update, const Variant& value_proposed, Property& property_current, const PropertiesProvider* source );
		friend class wosh::PropertiesProvider;
//@}
/** @name Internal Mehods and Events management
 * @{
 ******************************************************************************/
	protected:
		friend class wosh::Device;
	private:
		/**
		 * @brief  Access the DeviceManager singleton. Gamma Pattern.
		 *         Static reference is allocated and detroyed by WoshKernel on constructor/destructor respectively
		 * @return pointer to DeviceManager singleton. May be NULL (if kernel has not been allocated yet)
		 */
		static DeviceManager* getInstance();

		/**
		 * @brief  Append a device-event to event-log cache. Reentrant.
		 * @param message [in] the message representing the devic-event (from Device bus, containing wosh::Fact)
		 * @see    eventsLog
		 */
		void logEvent( const Message& message );
		/**
		 * @brief  Register a Device. If a Device with same name exists, it is updated. Not Reentrant.
		 * @param device [in] the device object to be registered, ownership is acquired
		 * @param raise_event [in] when true, it will broadcast a Fact on wosh.Bus.Core
		 * @return WRET_ERR_PARAM if argument is NULL or its name is empty; WRET_OK else
		 * @see    registerDevice()
		 */
		WRESULT registerDevice_( Device* device, bool raise_event );
//@}
	private:
		Response* mmDoListDevicesByType( const Message* requestMessage );
		Response* mmDoRegisterDevice( const Request* request );
		Response* mmDoUnRegisterDevice( const Request* request );
		Response* mmDoFakeDeviceEvent( const Message* requestMessage );
		Response* mmDoEventsLog( const Request* request );
		WRESULT clearEventsLog();

	private:
		BusConnector BusDevices;	///< Bus of Devices, network-shared, created by myself on kernel-init

SharedMemoryEpidemic dsmDevices;	///< shared memory agent for the Devices dataset
		tStrDeviceMap devices;		///< map of pairs [device-name, Device*] (Device* holds deviceInfo)

		tMessageList eventsLog;		///< cache of last events (Message.Fact) monitored on Device bus.
		long eventLogMaxSize;		///< size of the EventLog cache. 0 will disable logging
		bool eventLogLocallyOnly;	///< when enabled (default), filter only local events


}; // class def


/**
 * @class   wosh::DeviceManager_DeviceUpdated
 * @brief   Raised when an device is added or updated.
 *
 * Internally, data is stored as wosh::List. Supports also wosh::Variant type.
 *
 * Fields are:
 *  - \c username [Variant::STRING] (always present, first item of the list)
 *  - \c action type (optional, default: new user)
 *
 * Some getters are provided for convenience:
 * \code

 * \endcode
 *
 * @see     wosh::Fact
 * @see     wosh::DeviceManager
 ****************************************************************************
 * @version 0.8.399 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class DeviceManager_DeviceUpdated : public wosh::Fact
 {
	WOSH_SERIALIZABLE(wosh::DeviceManager_DeviceUpdated)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		DeviceManager_DeviceUpdated()
			: wosh::Fact(_DeviceManager_EVENT_DeviceUpdated) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param device_name [in] name of the (updated) group
		 */
		DeviceManager_DeviceUpdated( const std::string& device_name );
		/**
		 * @brief  Constructor with initializers.
		 * @param device_name [in] name of the (updated) group
		 * @param device_action [in] update type: 0=updated; 1=new_group
		 */
		DeviceManager_DeviceUpdated( const std::string& device_name, short device_action = 1 );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		DeviceManager_DeviceUpdated( const DeviceManager_DeviceUpdated& m )
			: wosh::Fact(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~DeviceManager_DeviceUpdated() { }

	public:
		/**
		 * @brief   Get name of the (updated) group
		 * @return  groupname as string
		 */
		std::string getDeviceName() const;

		short getDeviceAction() const;

		inline bool isDeviceUpdated() const			{ return (getDeviceAction() == 0); }
		inline bool isDeviceNew() const				{ return (getDeviceAction() == 1); }
		inline bool isDeviceRemoved() const			{ return (getDeviceAction() == 2); }

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_DeviceManager_H__
